#ifndef _TD_BASIC_ENTITY_H_
#define _TD_BASIC_ENTITY_H_

/************************************************************************/
/* BOOST                                                                */
/************************************************************************/
#include <boost/smart_ptr/shared_ptr.hpp>

/************************************************************************/
/* STL                                                                  */
/************************************************************************/
#include <vector>

/************************************************************************/
/* SDL                                                                  */
/************************************************************************/
#include "SDL/SDL.h"

/************************************************************************/
/* Core                                                                 */
/************************************************************************/
#include "Core/Coord2D.h"
#include "Core/BaseShape.h"
#include "Core/Utils.h"

/************************************************************************/
/* Resources                                                            */
/************************************************************************/
#include "Resources/Images/SDLImage.h"

using namespace std;
using namespace boost;
using namespace TD_Resources;


namespace TD_Core {

	/** Base entity:
		Keeps track of the simplest object in the enviroment.
	  */

	class BaseEntity {
	
		/************************************************************************/
		/* Private functions                                                    */
		/************************************************************************/
		bool initValues();

	protected:	

		/** Basic coordinates info:
			Mutability: The geometric properties of one game object 
			should be flexible*/
		mutable Coord2D m_position;
		mutable float m_rotationAngle;
		
		/**The shapes vector, used for collision detection*/
		mutable vector <BaseShape *> m_shapes;

		/************************************************************************/
		/* Protected functions                                                  */
		/************************************************************************/
		virtual void blitSurface(SDL_Surface *const g_destSurface, SDL_Rect *g_pClippingRect = NULL) const;
		void blitSurface(SDL_Surface *g_srcSurface, SDL_Surface *const g_destSurface, const Coord2D &g_position, SDL_Rect *g_pClippingRect = NULL) const ;


	public:
		
		/************************************************************************/
		/* Constructors				                                            */
		/************************************************************************/
		//Constructor default
		explicit BaseEntity();
		
		//Copy constructor 
		explicit BaseEntity(const BaseEntity &rhs);
		
		//Assignment constructor
		BaseEntity & operator=(const BaseEntity &rhs);
		
		//Initialization constructor
		explicit BaseEntity(Coord2D g_position, float g_rotationAngle = 0);
		
		~BaseEntity();
		
		/************************************************************************/
		/* Access functions                                                     */
		/************************************************************************/

		inline const vector<BaseShape *> & getShapesVector() const {
			return(m_shapes);
		}

		inline const Coord2D & getPosition() const {
			return (m_position);
		}

		/** If it is modifying mutable parameters it could be const */
		inline void setPosition(const Coord2D & g_position) const {
			m_position = g_position;
			for(unsigned int i = 0; i < m_shapes.size(); i++) {
				m_shapes[i]->setPosition(g_position - m_shapes[i]->getBoundaries()/2);
			}
		}
		/** If it is modifying mutable parameters it could be const */
		inline void setPosition(int x, int y) const {
			m_position.x = x;
			m_position.y = y;
			for(unsigned int i = 0; i < m_shapes.size(); i++) {
				m_shapes[i]->setPosition(m_position - m_shapes[i]->getBoundaries()/2);
			}
		}

		inline void translate(const Coord2D &g_translate) const {
			m_position += g_translate;
			for(unsigned int i = 0; i < m_shapes.size(); i++) {
				m_shapes[i]->setPosition(m_position - m_shapes[i]->getBoundaries()/2);
			}
		}

		inline void translate(int x, int y) const {
			m_position.x += x;
			m_position.y += y;
			for(unsigned int i = 0; i < m_shapes.size(); i++) {
				m_shapes[i]->setPosition(m_position - m_shapes[i]->getBoundaries()/2);
			}
		}

		inline float getRotationAngle() const {
			return m_rotationAngle;
		}
		
		/** If it is modifying mutable parameters it could be const */
		inline void setRotationAngle(float g_rotationAngle) const {
			m_rotationAngle = g_rotationAngle;
		}

		/************************************************************************/
		/* Inherent functionalities                                             */
		/************************************************************************/
		/** Collision checking:*/
		inline virtual bool collisionCheck(const BaseEntity &other) const {
			bool collided = false;
			for(unsigned int i = 0; i < m_shapes.size(); i++) {
				for(unsigned int j = 0; j < other.getShapesVector().size(); j++) {
					collided = collided || m_shapes[i]->collisionCheck(other.getShapesVector()[j]);
				}
			}
			return collided;
		}
		inline virtual bool collisionCheck(const Coord2D &position) const {
			bool collided = false;
			for(unsigned int i = 0; i < m_shapes.size(); i++) {
				collided = collided || m_shapes[i]->collisionCheck(position);
			}
			return collided;
		}

		/************************************************************************/
		/* Rendering                                                            */
		/************************************************************************/
		/** Pure virtual render function:*/
		virtual void render(SDL_Surface *const g_destSurface, unsigned int deltaTime) = 0;

	};

}

#endif
